/**
 * Copyright (C) 2009 SC 4ViewSoft SRL
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package math.spbu.ru.historycharts.charts;

import java.util.List;

import math.spbu.ru.historycharts.renderer.DefaultRenderer;
import math.spbu.ru.historycharts.renderer.SimpleSeriesRenderer;
import math.spbu.ru.historycharts.renderer.XYMultipleSeriesRenderer;
import math.spbu.ru.historycharts.renderer.XYMultipleSeriesRenderer.Orientation;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;

public abstract class AbstractChart {

	/**
	 * The graphical representation of the chart.
	 * 
	 * @param canvas
	 *            the canvas to paint to
	 * @param x
	 *            the top left x value of the view to draw to
	 * @param y
	 *            the top left y value of the view to draw to
	 * @param width
	 *            the width of the view to draw to
	 * @param height
	 *            the height of the view to draw to
	 */
	public abstract void draw(Canvas canvas, int x, int y, int width, int height);

	/**
	 * Draws the chart background.
	 * 
	 * @param renderer
	 *            the chart renderer
	 * @param canvas
	 *            the canvas to paint to
	 * @param x
	 *            the top left x value of the view to draw to
	 * @param y
	 *            the top left y value of the view to draw to
	 * @param width
	 *            the width of the view to draw to
	 * @param height
	 *            the height of the view to draw to
	 * @param paint
	 *            the paint used for drawing
	 */
	protected void drawBackground(DefaultRenderer renderer, Canvas canvas, int x, int y, int width, int height,
			Paint paint) {
		if (renderer.isApplyBackgroundColor()) {
			paint.setColor(renderer.getBackgroundColor());
			paint.setStyle(Style.FILL);
			canvas.drawRect(x, y, x + width, y + height, paint);
		}
	}

	/**
	 * Draws the chart legend.
	 * 
	 * @param canvas
	 *            the canvas to paint to
	 * @param renderer
	 *            the series renderer
	 * @param titles
	 *            the titles to go to the legend
	 * @param left
	 *            the left X value of the area to draw to
	 * @param right
	 *            the right X value of the area to draw to
	 * @param y
	 *            the y value of the area to draw to
	 * @param width
	 *            the width of the area to draw to
	 * @param height
	 *            the height of the area to draw to
	 * @param legendSize
	 *            the legend size
	 * @param paint
	 *            the paint to be used for drawing
	 */
	protected void drawLegend(Canvas canvas, DefaultRenderer renderer, List<String> titles, int left, int right, int y,
			int width, int height, int legendSize, Paint paint) {

		if (!renderer.isShowLegend())
			return;

		float currentX = left;
		float currentY = y + height - legendSize + 32;
		final float lineSize = getLegendShapeWidth();
		paint.setTextAlign(Align.LEFT);
		paint.setTextSize(12);
		//min(titles.size, 
		int sLength = titles.size();
		for (int i = 0; i < sLength; i++) {
			String text = titles.get(i);
			paint.setColor(renderer.getSeriesRendererAt(i).getColor());
			
			float[] widths = new float[text.length()];
			paint.getTextWidths(text, widths);
			float sum = 0;
			for (float value : widths) {
				sum += value;
			}
			float extraSize = lineSize + 10 + sum;
			float currentWidth = currentX + extraSize;

			if (i > 0 && getExceed(currentWidth, renderer, right, width)) {
				currentX = left;
				currentY += 15;
				currentWidth = currentX + extraSize;
			}
			if (getExceed(currentWidth, renderer, right, width)) {
				float maxWidth = right - currentX - lineSize - 10;
				if (isVertical(renderer)) {
					maxWidth = width - currentX - lineSize - 10;
				}
				int nr = paint.breakText(text, true, maxWidth, widths);
				text = text.substring(0, nr) + "...";
			}
			drawLegendShape(canvas, renderer.getSeriesRendererAt(i), currentX, currentY, paint);
			canvas.drawText(text, currentX + lineSize + 5, currentY + 5, paint);
			currentX += extraSize;
		}
	}

	private boolean getExceed(float currentWidth, DefaultRenderer renderer, int right, int width) {
		boolean exceed = currentWidth > right;
		if (isVertical(renderer)) {
			exceed = currentWidth > width;
		}
		return exceed;
	}

	private boolean isVertical(DefaultRenderer renderer) {
		// TODO: make XYMultipleSeriesRenderer
		 return renderer instanceof XYMultipleSeriesRenderer &&
		 ((XYMultipleSeriesRenderer) renderer).getOrientation() ==
		 Orientation.VERTICAL;
	}
	
	/**
     * The graphical representation of a path.
     *
     * @param canvas   the canvas to paint to
     * @param points   the points that are contained in the path to paint
     * @param paint    the paint to be used for painting
     * @param circular if the path ends with the start point
     */
    protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {
        Path path = new Path();
        path.moveTo(points[0], points[1]);
        for (int i = 2; i < points.length; i += 2) {
            path.lineTo(points[i], points[i + 1]);
        }
        if (circular) {
            path.lineTo(points[0], points[1]);
        }
        // paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(3);
        canvas.drawPath(path, paint);
        paint.setStrokeWidth(0);
    }

	public abstract int getLegendShapeWidth();

	public abstract void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y, Paint paint);
}
